﻿// This software is the confidential and proprietary information of NetBay.
// Such confidential information should not be disclosed.
// NetBay copyright(c) 2012

#region

using System;
using System.Collections.Generic;
using NetBay.Core.BusinessEntities;
using NetBay.Core.BusinessEntities.Workflow;
using NetBay.Core.BusinessEntities.Workflow.Rules;
using Rio.Workflow.Runtime.Enums;
using Rio.Workflow.Runtime.Events;

#endregion

namespace Rio.Workflow.Runtime
{
    public abstract class WorkflowContextBase : IDisposable
    {
        #region Fields

        private string _name;
        private Rules _rulesExecutor;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkflowContextBase" /> class.
        /// </summary>
        public WorkflowContextBase()
        {
            IsActionMode = false;
        }

        #endregion

        #region Instance Properties

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public virtual string Name
        {
            get { return string.IsNullOrEmpty(_name) ? _name : CurrentDefinition.AssemblyName; }
        }

        /// <summary>
        /// Gets or sets the creation context.
        /// </summary>
        /// <value>The creation context.</value>
        public CreationContext CreationContext { get; internal set; }

        /// <summary>
        /// Gets or sets the current action.
        /// </summary>
        /// <value>The current action.</value>
        public WorkflowAction CurrentAction { get; internal set; }

        /// <summary>
        /// Gets or sets the current definition.
        /// </summary>
        /// <value>The current definition.</value>
        public WorkflowDefinition CurrentDefinition { get; internal set; }

        /// <summary>
        /// Gets or sets the state of the current doc.
        /// </summary>
        /// <value>The state of the current doc.</value>
        public List<WorkflowDocument> CurrentDocState { get; internal set; }

        /// <summary>
        /// Gets or sets the current instance.
        /// </summary>
        /// <value>The current instance.</value>
        public WorkflowInstance CurrentInstance { get; internal set; }

        /// <summary>
        /// Gets or sets the is action mode.
        /// </summary>
        /// <value>The is action mode.</value>
        public bool IsActionMode { get; set; }

        /// <summary>
        /// Gets or sets the is creation mode.
        /// </summary>
        /// <value>The is creation mode.</value>
        public bool IsCreationMode { get; set; }

        /// <summary>
        /// Gets or sets the current instance.
        /// </summary>
        /// <value>The current instance.</value>
        public WorkflowInstance OriginalInstance { get; internal set; }

        /// <summary>
        /// Gets or sets the user id.
        /// </summary>
        /// <value>The user id.</value>
        public long RguId { get; internal set; }

        /// <summary>
        /// Gets the get rules helper.
        /// </summary>
        /// <value>The get rules helper.</value>
        public Rules RulesHelper
        {
            get
            {
                if (_rulesExecutor == null)
                {
                    _rulesExecutor = Rules.Deserialize(CurrentDefinition.Rules);
                }
                return _rulesExecutor;
            }
        }

        /// <summary>
        /// Gets or sets the user id.
        /// </summary>
        /// <value>The user id.</value>
        public long UserId { get; internal set; }

        #endregion

        #region Instance Methods

        /// <summary>
        /// Starts the workflow.
        /// </summary>
        /// <param name="wkfDefinition">The WKF definition.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public abstract WorkflowInstance StartWorkflow(WorkflowDefinition wkfDefinition, CreationContext context);

        /// <summary>
        /// Workflows can start.
        /// </summary>
        /// <param name="wkfDefinition">The WKF definition.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public abstract bool WorkflowCanStart(WorkflowDefinition wkfDefinition, CreationContext context);

        /// <summary>
        /// Workflows the opened.
        /// </summary>
        public abstract void WorkflowOpened();

        /// <summary>
        /// Requests the chrono.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public virtual Item RequestChrono(ChronoRequest request)
        {
            return new Item(0, string.Empty);
        }

        /// <summary>
        /// Resolveds the receiver.
        /// </summary>
        /// <returns></returns>
        public virtual long? ResolvedNextHierarchicalReceiverId()
        {
            return null;
        }

        /// <summary>
        /// Executes the action.
        /// </summary>
        /// <param name="executor">The executor.</param>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        internal abstract ActionResult ExecuteAction(IActionExecutor executor, ActionRequest request);

        /// <summary>
        /// Initializes the action context.
        /// </summary>
        /// <param name="currentDefinition">The current definition.</param>
        /// <param name="currentInstance">The current instance.</param>
        /// <param name="currentAction">The current action.</param>
        /// <param name="currentDocState"></param>
        /// <param name="rguId">The rgu id.</param>
        /// <param name="userId">The user id.</param>
        internal void InitializeActionContext(WorkflowDefinition currentDefinition, WorkflowInstance currentInstance,
                                              WorkflowAction currentAction, List<WorkflowDocument> currentDocState,
                                              long rguId, long userId)
        {
            IsActionMode = true;
            CurrentDefinition = currentDefinition;
            OriginalInstance = (WorkflowInstance) currentInstance.Clone();
            CurrentInstance = currentInstance;
            CurrentDocState = currentDocState;
            CurrentAction = currentAction;
            RguId = rguId;
            UserId = userId;
        }

        /// <summary>
        /// Initializes the creation context.
        /// </summary>
        /// <param name="currentDefinition">The current definition.</param>
        /// <param name="creationContext">The creation context.</param>
        /// <param name="rguId">The rgu id.</param>
        /// <param name="userId">The user id.</param>
        internal void InitializeCreationContext(WorkflowDefinition currentDefinition, CreationContext creationContext,
                                                long rguId, long userId)
        {
            IsCreationMode = true;
            CurrentDefinition = currentDefinition;
            CreationContext = creationContext;
            RguId = rguId;
            UserId = userId;
        }

        internal void RaiseAfterChronoRequest(Item request)
        {
            if (AfterChronoRequest != null)
                AfterChronoRequest(this, new ChronoResquestEventArgs(CurrentInstance, request));
        }

        internal void RaiseAfterExecuteAction()
        {
            if (AfterExecuteAction != null)
                AfterExecuteAction(this, new WorkflowEventArgs(CurrentInstance));
        }

        internal void RaiseBeforeChronoRequest()
        {
            if (BeforeChronoRequest != null)
                BeforeChronoRequest(this, new EventArgs());
        }

        internal void RaiseBeforeExecuteAction()
        {
            if (BeforeExecuteAction != null)
                BeforeExecuteAction(this, new WorkflowEventArgs(CurrentInstance));
        }

        internal void RaiseWorkflowFaulted()
        {
            if (WorkflowFaulted != null)
                WorkflowFaulted(this, new WorkflowFaultedEventArgs(CurrentInstance, null));
        }

        internal void RaiseWorkflowStarted()
        {
            if (WorkflowStarted != null)
                WorkflowStarted(this, new WorkflowEventArgs(CurrentInstance));
        }

        internal void RaiseWorkflowStarting()
        {
            if (WorkflowStarting != null)
                WorkflowStarting(this, new EventArgs());
        }

        /// <summary>
        /// Sets the creation context.
        /// </summary>
        /// <param name="context">The creation context.</param>
        internal void SetCreationContext(CreationContext context)
        {
            CreationContext = context;
        }

        /// <summary>
        /// Sets the current definition.
        /// </summary>
        /// <param name="wkfDefinition">The WKF definition.</param>
        internal void SetCurrentDefinition(WorkflowDefinition wkfDefinition)
        {
            CurrentDefinition = wkfDefinition;
        }

        #endregion

        #region Event Declarations

        public event WorkflowEventHandler AfterChronoRequest;
        public event WorkflowEventHandler AfterExecuteAction;
        public event EventHandler BeforeChronoRequest;
        public event WorkflowEventHandler BeforeExecuteAction;
        public event WorkflowEventHandler WorkflowFaulted;
        public event WorkflowEventHandler WorkflowStarted;
        public event EventHandler WorkflowStarting;

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing,
        /// or resetting unmanaged resources.
        /// </summary>
        public virtual void Dispose()
        {
            CreationContext = null;
            CurrentDefinition = null;
            CurrentInstance = null;
            CurrentDocState = null;
            _rulesExecutor = null;
        }

        #endregion
    }
}